home *** CD-ROM | disk | FTP | other *** search
/ Sprite 1984 - 1993 / Sprite 1984 - 1993.iso / src / daemons / lpd / printjob.c < prev    next >
C/C++ Source or Header  |  1992-05-17  |  33KB  |  1,464 lines

  1. /*
  2.  * Copyright (c) 1983 Regents of the University of California.
  3.  * All rights reserved.
  4.  *
  5.  * Redistribution and use in source and binary forms are permitted
  6.  * provided that this notice is preserved and that due credit is given
  7.  * to the University of California at Berkeley. The name of the University
  8.  * may not be used to endorse or promote products derived from this
  9.  * software without specific prior written permission. This software
  10.  * is provided ``as is'' without express or implied warranty.
  11.  */
  12.  
  13. #ifndef lint
  14. static char sccsid[] = "@(#)printjob.c    5.5 (Berkeley) 5/5/88";
  15. #endif /* not lint */
  16.  
  17. /*
  18.  * printjob -- print jobs in the queue.
  19.  *
  20.  *    NOTE: the lock file is used to pass information to lpq and lprm.
  21.  *    it does not need to be removed because file locks are dynamic.
  22.  */
  23.  
  24. #include "lp.h"
  25.  
  26. #ifdef sprite
  27. #include <proc.h>
  28. #include <fs.h>
  29. #endif
  30.  
  31. #define DORETURN    0    /* absorb fork error */
  32. #define DOABORT        1    /* abort if dofork fails */
  33.  
  34. /*
  35.  * Error tokens
  36.  */
  37. #define REPRINT        (-2)
  38. #define ERROR        (-1)
  39. #define    OK        0
  40. #define    FATALERR    1
  41. #define    NOACCT        2
  42. #define    FILTERERR    3
  43. #define    ACCESS        4
  44.  
  45. char    title[80];        /* ``pr'' title */
  46. FILE    *cfp;            /* control file */
  47. int    pfd;            /* printer file descriptor */
  48. int    ofd;            /* output filter file descriptor */
  49. int    lfd;            /* lock file descriptor */
  50. int    pid;            /* pid of lpd process */
  51. int    prchild;        /* id of pr process */
  52. int    child;            /* id of any filters */
  53. int    ofilter;        /* id of output filter, if any */
  54. int    tof;            /* true if at top of form */
  55. int    remote;            /* true if sending files to remote */
  56. dev_t    fdev;            /* device of file pointed to by symlink */
  57. ino_t    fino;            /* inode of file pointed to by symlink */
  58.  
  59. char    fromhost[32];        /* user's host machine */
  60. char    logname[32];        /* user's login name */
  61. char    jobname[100];        /* job or file name */
  62. char    class[32];        /* classification field */
  63. char    width[10] = "-w";    /* page width in characters */
  64. char    length[10] = "-l";    /* page length in lines */
  65. char    pxwidth[10] = "-x";    /* page width in pixels */
  66. char    pxlength[10] = "-y";    /* page length in pixels */
  67. char    indent[10] = "-i0";    /* indentation size in characters */
  68. char    tempfile[] = "errsXXXXXX"; /* file name for filter output */
  69. extern  int debug;
  70.  
  71. printjob()
  72. {
  73.     struct stat stb;
  74.     register struct queue *q, **qp;
  75.     struct queue **queue;
  76.     register int i, nitems;
  77.     long pidoff;
  78.     int count = 0;
  79.     extern int abortpr();
  80.  
  81.     init();                    /* set up capabilities */
  82.     (void) write(1, "", 1);            /* ack that daemon is started */
  83.     /*
  84.      * Make sure the spool directory exists.
  85.      */
  86.     if (stat(SD, &stb) < 0) {
  87.         mkdir(SD, 0775);
  88.     }
  89.     (void) close(2);            /* set up log file */
  90.     if (open(LF, O_CREAT|O_WRONLY|O_APPEND, 0664) < 0) {
  91.         syslog(LOG_ERR, "%s: %m", LF);
  92.         (void) open("/dev/null", O_WRONLY);
  93.     }
  94.     setgid(getegid());
  95.     pid = getpid();                /* for use with lprm */
  96.     setpgrp(0, pid);
  97.     signal(SIGHUP, abortpr);
  98.     signal(SIGINT, abortpr);
  99.     signal(SIGQUIT, abortpr);
  100.     signal(SIGTERM, abortpr);
  101.  
  102.     (void) mktemp(tempfile);
  103.  
  104.     /*
  105.      * uses short form file names
  106.      */
  107.     if (chdir(SD) < 0) {
  108.     }
  109.     if (stat(LO, &stb) == 0 && (stb.st_mode & 0100))
  110.         exit(0);        /* printing disabled */
  111.     lfd = open(LO, O_RDWR|O_CREAT, 0644);
  112.     if (lfd < 0) {
  113.         syslog(LOG_ERR, "%s: %s: %m", printer, LO);
  114.         exit(1);
  115.     }
  116.     if (flock(lfd, LOCK_EX|LOCK_NB) < 0) {
  117.         if (errno == EWOULDBLOCK) {    /* active deamon present */
  118. #if 1
  119.             char buf[0x100];
  120.             int xpid;
  121.  
  122.             read(lfd, buf, sizeof(buf));
  123.             xpid = atoi(buf);
  124.             if (kill(xpid, 0) != 0) {
  125.             syslog(LOG_ERR, "Lock error, pid 0x%x", xpid);
  126.  
  127.             ((void (*)()) 0) ();    /* force a seg viol */
  128.             abort();
  129.             }
  130. #endif
  131.             exit(0);
  132.         }
  133.         syslog(LOG_ERR, "%s: %s: %m", printer, LO);
  134.         exit(1);
  135.     }
  136.     ftruncate(lfd, 0);
  137.     /*
  138.      * write process id for others to know
  139.      */
  140.     sprintf(line, "%u\n", pid);
  141.     pidoff = i = strlen(line);
  142.     if (write(lfd, line, i) != i) {
  143.         syslog(LOG_ERR, "%s: %s: %m", printer, LO);
  144.         exit(1);
  145.     }
  146.     /*
  147.      * search the spool directory for work and sort by queue order.
  148.      */
  149.     if ((nitems = getq(&queue)) < 0) {
  150.         syslog(LOG_ERR, "%s: can't scan %s", printer, SD);
  151.         exit(1);
  152.     }
  153.     if (nitems == 0)        /* no work to do */
  154.         exit(0);
  155.     if (stb.st_mode & 01) {        /* reset queue flag */
  156.         if (fchmod(lfd, stb.st_mode & 0776) < 0)
  157.             syslog(LOG_ERR, "%s: %s: %m", printer, LO);
  158.     }
  159.     openpr();            /* open printer or remote */
  160. again:
  161.     /*
  162.      * we found something to do now do it --
  163.      *    write the name of the current control file into the lock file
  164.      *    so the spool queue program can tell what we're working on
  165.      */
  166.     for (qp = queue; nitems--; free((char *) q)) {
  167.         q = *qp++;
  168.         if (stat(q->q_name, &stb) < 0)
  169.             continue;
  170.     restart:
  171.         (void) lseek(lfd, pidoff, 0);
  172.         (void) sprintf(line, "%s\n", q->q_name);
  173.         i = strlen(line);
  174.         if (write(lfd, line, i) != i)
  175.             syslog(LOG_ERR, "%s: %s: %m", printer, LO);
  176.         if (!remote)
  177.             i = printit(q->q_name);
  178.         else
  179.             i = sendit(q->q_name);
  180.         /*
  181.          * Check to see if we are supposed to stop printing or
  182.          * if we are to rebuild the queue.
  183.          */
  184.         if (fstat(lfd, &stb) == 0) {
  185.             /* stop printing before starting next job? */
  186.             if (stb.st_mode & 0100)
  187.                 goto done;
  188.             /* rebuild queue (after lpc topq) */
  189.             if (stb.st_mode & 01) {
  190.                 for (free((char *) q); nitems--; free((char *) q))
  191.                     q = *qp++;
  192.                 if (fchmod(lfd, stb.st_mode & 0776) < 0)
  193.                     syslog(LOG_WARNING, "%s: %s: %m",
  194.                         printer, LO);
  195.                 break;
  196.             }
  197.         }
  198.         if (i == OK)        /* file ok and printed */
  199.             count++;
  200.         else if (i == REPRINT) { /* try reprinting the job */
  201.             syslog(LOG_INFO, "restarting %s", printer);
  202.             if (ofilter > 0) {
  203.                 kill(ofilter, SIGCONT);    /* to be sure */
  204.                 (void) close(ofd);
  205.                 while ((i = wait(0)) > 0 && i != ofilter)
  206.                     ;
  207.                 ofilter = 0;
  208.             }
  209.             (void) close(pfd);    /* close printer */
  210.             if (ftruncate(lfd, pidoff) < 0)
  211.                 syslog(LOG_WARNING, "%s: %s: %m", printer, LO);
  212.             openpr();        /* try to reopen printer */
  213.             goto restart;
  214.         }
  215.     }
  216.     free((char *) queue);
  217.     /*
  218.      * search the spool directory for more work.
  219.      */
  220.     if ((nitems = getq(&queue)) < 0) {
  221.         syslog(LOG_ERR, "%s: can't scan %s", printer, SD);
  222.         exit(1);
  223.     }
  224.     if (nitems == 0) {        /* no more work to do */
  225.     done:
  226.         if (count > 0) {    /* Files actually printed */
  227.             if (!SF && !tof)
  228.                 (void) write(ofd, FF, strlen(FF));
  229.             if (TR != NULL)        /* output trailer */
  230.                 (void) write(ofd, TR, strlen(TR));
  231.         }
  232.         (void) unlink(tempfile);
  233.         exit(0);
  234.     }
  235.     goto again;
  236. }
  237.  
  238. char    fonts[4][50];    /* fonts for troff */
  239.  
  240. char ifonts[4][18] = {
  241.     "/usr/lib/vfont/R",
  242.     "/usr/lib/vfont/I",
  243.     "/usr/lib/vfont/B",
  244.     "/usr/lib/vfont/S"
  245. };
  246.  
  247. /*
  248.  * The remaining part is the reading of the control file (cf)
  249.  * and performing the various actions.
  250.  */
  251. printit(file)
  252.     char *file;
  253. {
  254.     register int i;
  255.     char *cp;
  256.     int bombed = OK;
  257.  
  258.     /*
  259.      * open control file; ignore if no longer there.
  260.      */
  261.     if ((cfp = fopen(file, "r")) == NULL) {
  262.         syslog(LOG_INFO, "%s: %s: %m", printer, file);
  263.         return(OK);
  264.     }
  265.     /*
  266.      * Reset troff fonts.
  267.      */
  268.     for (i = 0; i < 4; i++)
  269.         strcpy(fonts[i], ifonts[i]);
  270.     strcpy(width+2, "0");
  271.     strcpy(indent+2, "0");
  272.  
  273.     /*
  274.      *      read the control file for work to do
  275.      *
  276.      *      file format -- first character in the line is a command
  277.      *      rest of the line is the argument.
  278.      *      valid commands are:
  279.      *
  280.      *        S -- "stat info" for symbolic link protection
  281.      *        J -- "job name" on banner page
  282.      *        C -- "class name" on banner page
  283.      *              L -- "literal" user's name to print on banner
  284.      *        T -- "title" for pr
  285.      *        H -- "host name" of machine where lpr was done
  286.      *              P -- "person" user's login name
  287.      *              I -- "indent" amount to indent output
  288.      *              f -- "file name" name of text file to print
  289.      *        l -- "file name" text file with control chars
  290.      *        p -- "file name" text file to print with pr(1)
  291.      *        t -- "file name" troff(1) file to print
  292.      *        n -- "file name" ditroff(1) file to print
  293.      *        d -- "file name" dvi file to print
  294.      *        g -- "file name" plot(1G) file to print
  295.      *        v -- "file name" plain raster file to print
  296.      *        c -- "file name" cifplot file to print
  297.      *        1 -- "R font file" for troff
  298.      *        2 -- "I font file" for troff
  299.      *        3 -- "B font file" for troff
  300.      *        4 -- "S font file" for troff
  301.      *        N -- "name" of file (used by lpq)
  302.      *              U -- "unlink" name of file to remove
  303.      *                    (after we print it. (Pass 2 only)).
  304.      *        M -- "mail" to user when done printing
  305.      *
  306.      *      getline reads a line and expands tabs to blanks
  307.      */
  308.  
  309.     /* pass 1 */
  310.  
  311.     while (getline(cfp)) {
  312.         switch (line[0]) {
  313.         case 'H':
  314.             strcpy(fromhost, line+1);
  315.             if (class[0] == '\0')
  316.                 strncpy(class, line+1, sizeof(class)-1);
  317.             continue;
  318.  
  319.         case 'P':
  320.             strncpy(logname, line+1, sizeof(logname)-1);
  321.             if (RS) {            /* restricted */
  322.                 if (getpwnam(logname) == (struct passwd *)0) {
  323.                     bombed = NOACCT;
  324.                     sendmail(line+1, bombed);
  325.                     goto pass2;
  326.                 }
  327.             }
  328.             continue;
  329.  
  330.         case 'S':
  331.             cp = line+1;
  332.             i = 0;
  333.             while (*cp >= '0' && *cp <= '9')
  334.                 i = i * 10 + (*cp++ - '0');
  335.             fdev = i;
  336.             cp++;
  337.             i = 0;
  338.             while (*cp >= '0' && *cp <= '9')
  339.                 i = i * 10 + (*cp++ - '0');
  340.             fino = i;
  341.             continue;
  342.  
  343.         case 'J':
  344.             if (line[1] != '\0')
  345.                 strncpy(jobname, line+1, sizeof(jobname)-1);
  346.             else
  347.                 strcpy(jobname, " ");
  348.             continue;
  349.  
  350.         case 'C':
  351.             if (line[1] != '\0')
  352.                 strncpy(class, line+1, sizeof(class)-1);
  353.             else if (class[0] == '\0')
  354.                 gethostname(class, sizeof(class));
  355.             continue;
  356.  
  357.         case 'T':    /* header title for pr */
  358.             strncpy(title, line+1, sizeof(title)-1);
  359.             continue;
  360.  
  361.         case 'L':    /* identification line */
  362.             if (!SH && !HL)
  363.                 banner(line+1, jobname);
  364.             continue;
  365.  
  366.         case '1':    /* troff fonts */
  367.         case '2':
  368.         case '3':
  369.         case '4':
  370.             if (line[1] != '\0')
  371.                 strcpy(fonts[line[0]-'1'], line+1);
  372.             continue;
  373.  
  374.         case 'W':    /* page width */
  375.             strncpy(width+2, line+1, sizeof(width)-3);
  376.             continue;
  377.  
  378.         case 'I':    /* indent amount */
  379.             strncpy(indent+2, line+1, sizeof(indent)-3);
  380.             continue;
  381.  
  382.         default:    /* some file to print */
  383.             i = print(line[0], line+1);
  384.             if (debug)
  385.                 syslog(LOG_ERR, "print(%s)=%d", line, i);
  386.             switch (i) {
  387.             case ERROR:
  388.                 if (bombed == OK)
  389.                     bombed = FATALERR;
  390.                 break;
  391.             case REPRINT:
  392.                 (void) fclose(cfp);
  393.                 return(REPRINT);
  394.             case FILTERERR:
  395.             case ACCESS:
  396.                 bombed = i;
  397.                 sendmail(logname, bombed);
  398.             }
  399.             title[0] = '\0';
  400.             continue;
  401.  
  402.         case 'N':
  403.         case 'U':
  404.         case 'M':
  405.             continue;
  406.         }
  407.     }
  408.     /* pass 2 */
  409.  
  410. pass2:
  411.     fseek(cfp, 0L, 0);
  412.     while (getline(cfp)) {
  413.         switch (line[0]) {
  414.         case 'L':    /* identification line */
  415.             if (!SH && HL)
  416.                 banner(line+1, jobname);
  417.             continue;
  418.  
  419.         case 'M':
  420.             if (bombed < NOACCT)    /* already sent if >= NOACCT */
  421.                 sendmail(line+1, bombed);
  422.             continue;
  423.  
  424.         case 'U':
  425.             (void) unlink(line+1);
  426.         }
  427.     }
  428.     /*
  429.      * clean-up in case another control file exists
  430.      */
  431.     (void) fclose(cfp);
  432.     (void) unlink(file);
  433.     return(bombed == OK ? OK : ERROR);
  434. }
  435.  
  436. /*
  437.  * Print a file.
  438.  * Set up the chain [ PR [ | {IF, OF} ] ] or {IF, RF, TF, NF, DF, CF, VF}.
  439.  * Return -1 if a non-recoverable error occured,
  440.  * 2 if the filter detected some errors (but printed the job anyway),
  441.  * 1 if we should try to reprint this job and
  442.  * 0 if all is well.
  443.  * Note: all filters take stdin as the file, stdout as the printer,
  444.  * stderr as the log file, and must not ignore SIGINT.
  445.  */
  446. print(format, file)
  447.     int format;
  448.     char *file;
  449. {
  450.     register int n;
  451.     register char *prog;
  452.     int fi, fo;
  453.     char *av[15], buf[BUFSIZ];
  454.     int pid, p[2], stopped = 0;
  455.     union wait status;
  456.     struct stat stb;
  457.  
  458.     if (lstat(file, &stb) < 0 || (fi = open(file, O_RDONLY)) < 0) {
  459.         if (debug)
  460.         syslog(LOG_ERR, "can't open %s: %m", file);
  461.         return(ERROR);
  462.     }
  463.  
  464.     if (debug) {
  465.         struct stat statBuf;
  466.  
  467.         if (fstat(fi, &statBuf)) {
  468.         syslog(LOG_ERR, "fstat failed: %m");
  469.         exit(1);
  470.         }
  471.  
  472.         syslog(LOG_ERR, "FI: file=|%s| st_size=%d, st_mode=0x%x",
  473.         file, statBuf.st_size, statBuf.st_mode);
  474.     }
  475.  
  476.     /*
  477.      * Check to see if data file is a symbolic link. If so, it should
  478.      * still point to the same file or someone is trying to print
  479.      * something he shouldn't.
  480.      */
  481.     if ((stb.st_mode & S_IFMT) == S_IFLNK && fstat(fi, &stb) == 0 &&
  482.         (stb.st_dev != fdev || stb.st_ino != fino)) {
  483.         if (debug)
  484.             syslog(LOG_ERR, "access denied for %s: %m", file);
  485.         return(ACCESS);
  486.     }
  487.     if (!SF && !tof) {        /* start on a fresh page */
  488.         (void) write(ofd, FF, strlen(FF));
  489.         tof = 1;
  490.     }
  491.     if (IF == NULL && (format == 'f' || format == 'l')) {
  492.         tof = 0;
  493.         while ((n = read(fi, buf, BUFSIZ)) > 0)
  494.             if (write(ofd, buf, n) != n) {
  495.                 (void) close(fi);
  496.                 if (debug)
  497.                     syslog(LOG_ERR, "write err: %m");
  498.                 return(REPRINT);
  499.             }
  500.         (void) close(fi);
  501.         return(OK);
  502.     }
  503.     switch (format) {
  504.     case 'p':    /* print file using 'pr' */
  505.         if (IF == NULL) {    /* use output filter */
  506.             prog = PR;
  507.             av[0] = "pr";
  508.             av[1] = width;
  509.             av[2] = length;
  510.             av[3] = "-h";
  511.             av[4] = *title ? title : " ";
  512.             av[5] = 0;
  513.             fo = ofd;
  514.             goto start;
  515.         }
  516.         pipe(p);
  517.         if ((prchild = dofork(DORETURN)) == 0) {    /* child */
  518.             dup2(fi, 0);        /* file is stdin */
  519.             dup2(p[1], 1);        /* pipe is stdout */
  520.             if (debug) {
  521.                 syslog(LOG_ERR, "execing %s %s, %s, %s, %s, %s",
  522.                   PR, "pr", width, length, "-h", *title?title:"");
  523.             }
  524.             for (n = 3; n < NOFILE; n++)
  525.                 (void) close(n);
  526.             execl(PR, "pr", width, length, "-h",
  527.                 *title ? title : " ", 0);
  528.             syslog(LOG_ERR, "cannot execl %s", PR);
  529.             exit(2);
  530.         }
  531.         (void) close(p[1]);        /* close output side */
  532.         (void) close(fi);
  533.         if (prchild < 0) {
  534.             prchild = 0;
  535.             (void) close(p[0]);
  536.             if (debug)
  537.                 syslog(LOG_ERR, "fork failed: %m");
  538.             return(ERROR);
  539.         }
  540.         fi = p[0];            /* use pipe for input */
  541.     case 'f':    /* print plain text file */
  542.         prog = IF;
  543.         av[1] = width;
  544.         av[2] = length;
  545.         av[3] = indent;
  546.         n = 4;
  547.         break;
  548.     case 'l':    /* like 'f' but pass control characters */
  549.         prog = IF;
  550.         av[1] = "-c";
  551.         av[2] = width;
  552.         av[3] = length;
  553.         av[4] = indent;
  554.         n = 5;
  555.         break;
  556.     case 'r':    /* print a fortran text file */
  557.         prog = RF;
  558.         av[1] = width;
  559.         av[2] = length;
  560.         n = 3;
  561.         break;
  562.     case 't':    /* print troff output */
  563.     case 'n':    /* print ditroff output */
  564.     case 'd':    /* print tex output */
  565.         (void) unlink(".railmag");
  566.         if ((fo = creat(".railmag", FILMOD)) < 0) {
  567.             syslog(LOG_ERR, "%s: cannot create .railmag", printer);
  568.             (void) unlink(".railmag");
  569.         } else {
  570.             for (n = 0; n < 4; n++) {
  571.                 if (fonts[n][0] != '/')
  572.                     (void) write(fo, "/usr/lib/vfont/", 15);
  573.                 (void) write(fo, fonts[n], strlen(fonts[n]));
  574.                 (void) write(fo, "\n", 1);
  575.             }
  576.             (void) close(fo);
  577.         }
  578.         prog = (format == 't') ? TF : (format == 'n') ? NF : DF;
  579.         av[1] = pxwidth;
  580.         av[2] = pxlength;
  581.         n = 3;
  582.         break;
  583.     case 'c':    /* print cifplot output */
  584.         prog = CF;
  585.         av[1] = pxwidth;
  586.         av[2] = pxlength;
  587.         n = 3;
  588.         break;
  589.     case 'g':    /* print plot(1G) output */
  590.         prog = GF;
  591.         av[1] = pxwidth;
  592.         av[2] = pxlength;
  593.         n = 3;
  594.         break;
  595.     case 'v':    /* print raster output */
  596.         prog = VF;
  597.         av[1] = pxwidth;
  598.         av[2] = pxlength;
  599.         n = 3;
  600.         break;
  601.     default:
  602.         (void) close(fi);
  603.         syslog(LOG_ERR, "%s: illegal format character '%c'",
  604.             printer, format);
  605.         return(ERROR);
  606.     }
  607.     if ((av[0] = rindex(prog, '/')) != NULL)
  608.         av[0]++;
  609.     else
  610.         av[0] = prog;
  611.     av[n++] = "-n";
  612.     av[n++] = logname;
  613.     av[n++] = "-h";
  614.     av[n++] = fromhost;
  615.     av[n++] = AF;
  616.     av[n] = 0;
  617.     fo = pfd;
  618.     if (ofilter > 0) {        /* stop output filter */
  619.         write(ofd, "\031\1", 2);
  620.         while ((pid = wait3(&status, WUNTRACED, 0)) > 0 && pid != ofilter)
  621.         ;
  622.         if (status.w_stopval == WSTOPPED) {
  623.         stopped++;
  624.         } else {
  625.         if (status.w_retcode == 0) {
  626.             if (debug) {
  627.             extern char *XXXX;
  628.  
  629.             syslog(LOG_ERR,
  630.                 "%s: output filter [0x%x] exited (0), pid = 0x%x",
  631.                 printer, ofilter, pid);
  632.             syslog(LOG_ERR, "reason = %s", XXXX);
  633.             }
  634.  
  635.             kill(ofilter, SIGCONT);     /* just to be sure */
  636.  
  637.             ofilter = 0;
  638.         } else {
  639.             (void) close(fi);
  640.             syslog(LOG_WARNING, "%s: output filter died (%d)",
  641.             printer, status.w_retcode);
  642.             return(REPRINT);
  643.         }
  644.         }
  645.     }
  646. start:
  647.     if ((child = dofork(DORETURN)) == 0) {    /* child */
  648.         if (debug) {
  649.         struct stat statBuf;
  650.  
  651.         if (fstat(fi, &statBuf)) {
  652.             syslog(LOG_ERR, "fstat failed: %m");
  653.             exit(1);
  654.         }
  655.  
  656.         syslog(LOG_ERR, "FI2: file=|%s| st_size=%d, st_mode=0x%x",
  657.             file, statBuf.st_size, statBuf.st_mode);
  658.         }
  659.  
  660.         if (dup2(fi, 0)) {
  661.             syslog(LOG_ERR, "dup2 0 failed: %m");
  662.             exit(1);
  663.         }
  664.         if (dup2(fo, 1)) {
  665.             syslog(LOG_ERR, "dup2 0 failed: %m");
  666.             exit(1);
  667.         }
  668. #ifdef sprite
  669.         /*
  670.          * Divert filter errors to /dev/syslog so users have
  671.          * some idea of what the hell happened to their job.
  672.          */
  673.         n = open("/dev/syslog", O_WRONLY);
  674. #else
  675.         n = open(tempfile, O_WRONLY|O_CREAT|O_TRUNC, 0664);
  676. #endif
  677.         if (n >= 0)
  678.             dup2(n, 2);
  679.         if (debug) {
  680.             struct stat statBuf;
  681.  
  682.             if (fstat(0, &statBuf)) {
  683.             syslog(LOG_ERR, "fstat failed: %m");
  684.             exit(1);
  685.             }
  686.  
  687.             syslog(LOG_ERR, "file=|%s| st_size=%d, st_mode=0x%x",
  688.             file, statBuf.st_size, statBuf.st_mode);
  689.  
  690.             syslog(LOG_ERR, "execing %s", prog);
  691.         }
  692.         for (n = 3; n < NOFILE; n++)
  693.             (void) close(n);
  694.         execv(prog, av);
  695.         syslog(LOG_ERR, "cannot execv %s", prog);
  696.         exit(2);
  697.     }
  698.     (void) close(fi);
  699.     if (child < 0) {
  700.         status.w_retcode = 100;
  701.     } else {
  702.         while ((pid = wait(&status)) > 0 && pid != child)
  703.         ;
  704.     }
  705.     child = 0;
  706.     prchild = 0;
  707.     if (stopped) {        /* restart output filter */
  708.         if (kill(ofilter, SIGCONT) < 0) {
  709.         syslog(LOG_ERR, "cannot restart output filter");
  710.         exit(1);
  711.         }
  712.     }
  713.     tof = 0;
  714.     if (!WIFEXITED(status)) {
  715.         syslog(LOG_WARNING, "%s: Daemon filter '%c' terminated (%d)",
  716.         printer, format, status.w_termsig);
  717.         return(ERROR);
  718.     }
  719.     switch (status.w_retcode) {
  720.     case 0:
  721.         tof = 1;
  722.         return(OK);
  723.     case 1:
  724.             if (debug) {
  725.             syslog(LOG_ERR, "%s: daemon filter `%c' wants REPRINT",
  726.             printer, format);
  727.         }
  728.         return(REPRINT);
  729.     default:
  730.         syslog(LOG_WARNING, "%s: Daemon filter '%c' exited (%d)",
  731.             printer, format, status.w_retcode);
  732.     case 2:
  733.             if (debug) {
  734.             syslog(LOG_ERR, "%s: ERROR in daemon filter `%c'",
  735.             printer, format);
  736.         }
  737.         return(ERROR);
  738.     }
  739. }
  740.  
  741. /*
  742.  * Send the daemon control file (cf) and any data files.
  743.  * Return -1 if a non-recoverable error occured, 1 if a recoverable error and
  744.  * 0 if all is well.
  745.  */
  746. sendit(file)
  747.     char *file;
  748. {
  749.     register int i, err = OK;
  750.     char *cp, last[BUFSIZ];
  751.  
  752.     /*
  753.      * open control file
  754.      */
  755.     if ((cfp = fopen(file, "r")) == NULL)
  756.         return(OK);
  757.     /*
  758.      *      read the control file for work to do
  759.      *
  760.      *      file format -- first character in the line is a command
  761.      *      rest of the line is the argument.
  762.      *      commands of interest are:
  763.      *
  764.      *            a-z -- "file name" name of file to print
  765.      *              U -- "unlink" name of file to remove
  766.      *                    (after we print it. (Pass 2 only)).
  767.      */
  768.  
  769.     /*
  770.      * pass 1
  771.      */
  772.     while (getline(cfp)) {
  773.     again:
  774.         if (line[0] == 'S') {
  775.             cp = line+1;
  776.             i = 0;
  777.             while (*cp >= '0' && *cp <= '9')
  778.                 i = i * 10 + (*cp++ - '0');
  779.             fdev = i;
  780.             cp++;
  781.             i = 0;
  782.             while (*cp >= '0' && *cp <= '9')
  783.                 i = i * 10 + (*cp++ - '0');
  784.             fino = i;
  785.             continue;
  786.         }
  787.         if (line[0] >= 'a' && line[0] <= 'z') {
  788.             strcpy(last, line);
  789.             while (i = getline(cfp))
  790.                 if (strcmp(last, line))
  791.                     break;
  792.             switch (sendfile('\3', last+1)) {
  793.             case OK:
  794.                 if (i)
  795.                     goto again;
  796.                 break;
  797.             case REPRINT:
  798.                 (void) fclose(cfp);
  799.                 return(REPRINT);
  800.             case ACCESS:
  801.                 sendmail(logname, ACCESS);
  802.             case ERROR:
  803.                 err = ERROR;
  804.             }
  805.             break;
  806.         }
  807.     }
  808.     if (err == OK && sendfile('\2', file) > 0) {
  809.         (void) fclose(cfp);
  810.         return(REPRINT);
  811.     }
  812.     /*
  813.      * pass 2
  814.      */
  815.     fseek(cfp, 0L, 0);
  816.     while (getline(cfp))
  817.         if (line[0] == 'U')
  818.             (void) unlink(line+1);
  819.     /*
  820.      * clean-up in case another control file exists
  821.      */
  822.     (void) fclose(cfp);
  823.     (void) unlink(file);
  824.     return(err);
  825. }
  826.  
  827. /*
  828.  * Send a data file to the remote machine and spool it.
  829.  * Return positive if we should try resending.
  830.  */
  831. sendfile(type, file)
  832.     char type, *file;
  833. {
  834.     register int f, i, amt;
  835.     struct stat stb;
  836.     char buf[BUFSIZ];
  837.     int sizerr, resp;
  838.  
  839.     if (lstat(file, &stb) < 0 || (f = open(file, O_RDONLY)) < 0)
  840.         return(ERROR);
  841.     /*
  842.      * Check to see if data file is a symbolic link. If so, it should
  843.      * still point to the same file or someone is trying to print something
  844.      * he shouldn't.
  845.      */
  846.     if ((stb.st_mode & S_IFMT) == S_IFLNK && fstat(f, &stb) == 0 &&
  847.         (stb.st_dev != fdev || stb.st_ino != fino))
  848.         return(ACCESS);
  849.     (void) sprintf(buf, "%c%d %s\n", type, stb.st_size, file);
  850.     amt = strlen(buf);
  851.     for (i = 0;  ; i++) {
  852.         if (write(pfd, buf, amt) != amt ||
  853.             (resp = response()) < 0 || resp == '\1') {
  854.             (void) close(f);
  855.             return(REPRINT);
  856.         } else if (resp == '\0')
  857.             break;
  858.         if (i == 0)
  859.             status("no space on remote; waiting for queue to drain");
  860.         if (i == 10)
  861.             syslog(LOG_ALERT, "%s: can't send to %s; queue full",
  862.                 printer, RM);
  863.         sleep(5 * 60);
  864.     }
  865.     if (i)
  866.         status("sending to %s", RM);
  867.     sizerr = 0;
  868.     for (i = 0; i < stb.st_size; i += BUFSIZ) {
  869.         amt = BUFSIZ;
  870.         if (i + amt > stb.st_size)
  871.             amt = stb.st_size - i;
  872.         if (sizerr == 0 && read(f, buf, amt) != amt)
  873.             sizerr = 1;
  874.         if (write(pfd, buf, amt) != amt) {
  875.             (void) close(f);
  876.             return(REPRINT);
  877.         }
  878.     }
  879.     (void) close(f);
  880.     if (sizerr) {
  881.         syslog(LOG_INFO, "%s: %s: changed size", printer, file);
  882.         /* tell recvjob to ignore this file */
  883.         (void) write(pfd, "\1", 1);
  884.         return(ERROR);
  885.     }
  886.     if (write(pfd, "", 1) != 1 || response())
  887.         return(REPRINT);
  888.     return(OK);
  889. }
  890.  
  891. /*
  892.  * Check to make sure there have been no errors and that both programs
  893.  * are in sync with eachother.
  894.  * Return non-zero if the connection was lost.
  895.  */
  896. response()
  897. {
  898.     char resp;
  899.  
  900.     if (read(pfd, &resp, 1) != 1) {
  901.         syslog(LOG_INFO, "%s: lost connection", printer);
  902.         return(-1);
  903.     }
  904.     return(resp);
  905. }
  906.  
  907. /*
  908.  * Banner printing stuff
  909.  */
  910. banner(name1, name2)
  911.     char *name1, *name2;
  912. {
  913.     time_t tvec;
  914.     extern char *ctime();
  915.  
  916.     time(&tvec);
  917.     if (!SF && !tof)
  918.         (void) write(ofd, FF, strlen(FF));
  919.     if (SB) {    /* short banner only */
  920.         if (class[0]) {
  921.             (void) write(ofd, class, strlen(class));
  922.             (void) write(ofd, ":", 1);
  923.         }
  924.         (void) write(ofd, name1, strlen(name1));
  925.         (void) write(ofd, "  Job: ", 7);
  926.         (void) write(ofd, name2, strlen(name2));
  927.         (void) write(ofd, "  Date: ", 8);
  928.         (void) write(ofd, ctime(&tvec), 24);
  929.         (void) write(ofd, "\n", 1);
  930.     } else {    /* normal banner */
  931.         (void) write(ofd, "\n\n\n", 3);
  932.         scan_out(ofd, name1, '\0');
  933.         (void) write(ofd, "\n\n", 2);
  934.         scan_out(ofd, name2, '\0');
  935.         if (class[0]) {
  936.             (void) write(ofd,"\n\n\n",3);
  937.             scan_out(ofd, class, '\0');
  938.         }
  939.         (void) write(ofd, "\n\n\n\n\t\t\t\t\tJob:  ", 15);
  940.         (void) write(ofd, name2, strlen(name2));
  941.         (void) write(ofd, "\n\t\t\t\t\tDate: ", 12);
  942.         (void) write(ofd, ctime(&tvec), 24);
  943.         (void) write(ofd, "\n", 1);
  944.     }
  945.     if (!SF)
  946.         (void) write(ofd, FF, strlen(FF));
  947.     tof = 1;
  948. }
  949.  
  950. char *
  951. scnline(key, p, c)
  952.     register char key, *p;
  953.     char c;
  954. {
  955.     register scnwidth;
  956.  
  957.     for (scnwidth = WIDTH; --scnwidth;) {
  958.         key <<= 1;
  959.         *p++ = key & 0200 ? c : BACKGND;
  960.     }
  961.     return (p);
  962. }
  963.  
  964. #define TRC(q)    (((q)-' ')&0177)
  965.  
  966. scan_out(scfd, scsp, dlm)
  967.     int scfd;
  968.     char *scsp, dlm;
  969. {
  970.     register char *strp;
  971.     register nchrs, j;
  972.     char outbuf[LINELEN+1], *sp, c, cc;
  973.     int d, scnhgt;
  974.     extern char scnkey[][HEIGHT];    /* in lpdchar.c */
  975.  
  976.     for (scnhgt = 0; scnhgt++ < HEIGHT+DROP; ) {
  977.         strp = &outbuf[0];
  978.         sp = scsp;
  979.         for (nchrs = 0; ; ) {
  980.             d = dropit(c = TRC(cc = *sp++));
  981.             if ((!d && scnhgt > HEIGHT) || (scnhgt <= DROP && d))
  982.                 for (j = WIDTH; --j;)
  983.                     *strp++ = BACKGND;
  984.             else
  985.                 strp = scnline(scnkey[c][scnhgt-1-d], strp, cc);
  986.             if (*sp == dlm || *sp == '\0' || nchrs++ >= PW/(WIDTH+1)-1)
  987.                 break;
  988.             *strp++ = BACKGND;
  989.             *strp++ = BACKGND;
  990.         }
  991.         while (*--strp == BACKGND && strp >= outbuf)
  992.             ;
  993.         strp++;
  994.         *strp++ = '\n';    
  995.         (void) write(scfd, outbuf, strp-outbuf);
  996.     }
  997. }
  998.  
  999. dropit(c)
  1000.     char c;
  1001. {
  1002.     switch(c) {
  1003.  
  1004.     case TRC('_'):
  1005.     case TRC(';'):
  1006.     case TRC(','):
  1007.     case TRC('g'):
  1008.     case TRC('j'):
  1009.     case TRC('p'):
  1010.     case TRC('q'):
  1011.     case TRC('y'):
  1012.         return (DROP);
  1013.  
  1014.     default:
  1015.         return (0);
  1016.     }
  1017. }
  1018.  
  1019. /*
  1020.  * sendmail ---
  1021.  *   tell people about job completion
  1022.  */
  1023. sendmail(user, bombed)
  1024.     char *user;
  1025.     int bombed;
  1026. {
  1027.     register int i;
  1028.     int p[2], s;
  1029.     register char *cp;
  1030.     char buf[100];
  1031.     struct stat stb;
  1032.     FILE *fp;
  1033.  
  1034.     pipe(p);
  1035.     if ((s = dofork(DORETURN)) == 0) {        /* child */
  1036.         dup2(p[0], 0);
  1037.         for (i = 3; i < NOFILE; i++)
  1038.             (void) close(i);
  1039.         if ((cp = rindex(MAIL, '/')) != NULL)
  1040.             cp++;
  1041.         else
  1042.             cp = MAIL;
  1043.         sprintf(buf, "%s@%s", user, fromhost);
  1044.         execl(MAIL, cp, buf, 0);
  1045.         exit(0);
  1046.     } else if (s > 0) {                /* parent */
  1047.         dup2(p[1], 1);
  1048.         printf("To: %s@%s\n", user, fromhost);
  1049.         printf("Subject: printer job\n\n");
  1050.         printf("Your printer job ");
  1051.         if (*jobname)
  1052.             printf("(%s) ", jobname);
  1053.         switch (bombed) {
  1054.         case OK:
  1055.             printf("\ncompleted successfully\n");
  1056.             break;
  1057.         default:
  1058.         case FATALERR:
  1059.             printf("\ncould not be printed\n");
  1060.             break;
  1061.         case NOACCT:
  1062.             printf("\ncould not be printed without an account on %s\n", host);
  1063.             break;
  1064.         case FILTERERR:
  1065.             if (stat(tempfile, &stb) < 0 || stb.st_size == 0 ||
  1066.                 (fp = fopen(tempfile, "r")) == NULL) {
  1067.                 printf("\nwas printed but had some errors\n");
  1068.                 break;
  1069.             }
  1070.             printf("\nwas printed but had the following errors:\n");
  1071.             while ((i = getc(fp)) != EOF)
  1072.                 putchar(i);
  1073.             (void) fclose(fp);
  1074.             break;
  1075.         case ACCESS:
  1076.             printf("\nwas not printed because it was not linked to the original file\n");
  1077.         }
  1078.         fflush(stdout);
  1079.         (void) close(1);
  1080.     }
  1081.     (void) close(p[0]);
  1082.     (void) close(p[1]);
  1083.     wait(&s);
  1084. }
  1085.  
  1086. /*
  1087.  * dofork - fork with retries on failure
  1088.  */
  1089. dofork(action)
  1090.     int action;
  1091. {
  1092.     register int i, pid;
  1093.  
  1094.     for (i = 0; i < 20; i++) {
  1095.         if ((pid = fork()) < 0) {
  1096.             sleep((unsigned)(i*i));
  1097.             continue;
  1098.         }
  1099.         /*
  1100.          * Child should run as daemon instead of root
  1101.          */
  1102.         if (pid == 0)
  1103.             setuid(DU);
  1104.         return(pid);
  1105.     }
  1106.     syslog(LOG_ERR, "can't fork");
  1107.  
  1108.     switch (action) {
  1109.     case DORETURN:
  1110.         return (-1);
  1111.     default:
  1112.         syslog(LOG_ERR, "bad action (%d) to dofork", action);
  1113.         /*FALL THRU*/
  1114.     case DOABORT:
  1115.         exit(1);
  1116.     }
  1117.     /*NOTREACHED*/
  1118. }
  1119.  
  1120. /*
  1121.  * Kill child processes to abort current job.
  1122.  */
  1123. abortpr()
  1124. {
  1125.         if (debug)
  1126.         syslog(LOG_ERR, "recieved signal, aborting");
  1127.  
  1128.     (void) unlink(tempfile);
  1129.  
  1130.     kill(0, SIGINT);
  1131.  
  1132.     if (ofilter > 0) {
  1133.         kill(ofilter, SIGCONT);
  1134.         close(ofd);
  1135.     }
  1136.  
  1137.     if (debug)
  1138.         syslog(LOG_ERR, "waiting for children to die");
  1139.  
  1140.     while (wait(0) > 0)
  1141.         ;
  1142.  
  1143.     if (debug)
  1144.         syslog(LOG_ERR, "all children are dead, exiting");
  1145.  
  1146.     exit(0);
  1147. }
  1148.  
  1149. init()
  1150. {
  1151.     int status;
  1152.  
  1153.     if ((status = pgetent(line, printer)) < 0) {
  1154.         syslog(LOG_ERR, "can't open printer description file");
  1155.         exit(1);
  1156.     } else if (status == 0) {
  1157.         syslog(LOG_ERR, "unknown printer: %s", printer);
  1158.         exit(1);
  1159.     }
  1160.     if ((LP = pgetstr("lp", &bp)) == NULL)
  1161.         LP = DEFDEVLP;
  1162.     if ((RP = pgetstr("rp", &bp)) == NULL)
  1163.         RP = DEFLP;
  1164.     if ((LO = pgetstr("lo", &bp)) == NULL)
  1165.         LO = DEFLOCK;
  1166.     if ((ST = pgetstr("st", &bp)) == NULL)
  1167.         ST = DEFSTAT;
  1168.     if ((LF = pgetstr("lf", &bp)) == NULL)
  1169.         LF = DEFLOGF;
  1170.     if ((SD = pgetstr("sd", &bp)) == NULL)
  1171.         SD = DEFSPOOL;
  1172.     if ((DU = pgetnum("du")) < 0)
  1173.         DU = DEFUID;
  1174.     if ((FF = pgetstr("ff", &bp)) == NULL)
  1175.         FF = DEFFF;
  1176.     if ((PW = pgetnum("pw")) < 0)
  1177.         PW = DEFWIDTH;
  1178.     sprintf(&width[2], "%d", PW);
  1179.     if ((PL = pgetnum("pl")) < 0)
  1180.         PL = DEFLENGTH;
  1181.     sprintf(&length[2], "%d", PL);
  1182.     if ((PX = pgetnum("px")) < 0)
  1183.         PX = 0;
  1184.     sprintf(&pxwidth[2], "%d", PX);
  1185.     if ((PY = pgetnum("py")) < 0)
  1186.         PY = 0;
  1187.     sprintf(&pxlength[2], "%d", PY);
  1188.     RM = pgetstr("rm", &bp);
  1189. #ifndef sprite
  1190.     /*
  1191.      * Figure out whether the local machine is the same as the remote 
  1192.      * machine entry (if it exists).  If not, then ignore the local
  1193.      * queue information.
  1194.      */
  1195.      if (RM != (char *) NULL) {
  1196.         char name[256];
  1197.         struct hostent *hp;
  1198.  
  1199.         /* get the standard network name of the local host */
  1200.         gethostname(name, sizeof(name));
  1201.         name[sizeof(name)-1] = '\0';
  1202.         hp = gethostbyname(name);
  1203.         if (hp == (struct hostent *) NULL) {
  1204.             syslog(LOG_ERR,
  1205.             "unable to get network name for local machine %s",
  1206.             name);
  1207.             goto localcheck_done;
  1208.         } else strcpy(name, hp->h_name);
  1209.  
  1210.         /* get the standard network name of RM */
  1211.         hp = gethostbyname(RM);
  1212.         if (hp == (struct hostent *) NULL) {
  1213.             syslog(LOG_ERR,
  1214.             "unable to get hostname for remote machine %s", RM);
  1215.             goto localcheck_done;
  1216.         }
  1217.  
  1218.         /* if printer is not on local machine, ignore LP */
  1219.         if (strcmp(name, hp->h_name) != 0) *LP = '\0';
  1220.     }
  1221. #endif /* sprite */
  1222. localcheck_done:
  1223.  
  1224.     AF = pgetstr("af", &bp);
  1225.     OF = pgetstr("of", &bp);
  1226.     IF = pgetstr("if", &bp);
  1227.     RF = pgetstr("rf", &bp);
  1228.     TF = pgetstr("tf", &bp);
  1229.     NF = pgetstr("nf", &bp);
  1230.     DF = pgetstr("df", &bp);
  1231.     GF = pgetstr("gf", &bp);
  1232.     VF = pgetstr("vf", &bp);
  1233.     CF = pgetstr("cf", &bp);
  1234.     TR = pgetstr("tr", &bp);
  1235.     RS = pgetflag("rs");
  1236.     SF = pgetflag("sf");
  1237.     SH = pgetflag("sh");
  1238.     SB = pgetflag("sb");
  1239.     HL = pgetflag("hl");
  1240.     RW = pgetflag("rw");
  1241.     BR = pgetnum("br");
  1242.     if ((FC = pgetnum("fc")) < 0)
  1243.         FC = 0;
  1244.     if ((FS = pgetnum("fs")) < 0)
  1245.         FS = 0;
  1246.     if ((XC = pgetnum("xc")) < 0)
  1247.         XC = 0;
  1248.     if ((XS = pgetnum("xs")) < 0)
  1249.         XS = 0;
  1250.     tof = !pgetflag("fo");
  1251. }
  1252.  
  1253. /*
  1254.  * Acquire line printer or remote connection.
  1255.  */
  1256. openpr()
  1257. {
  1258.     register int i, n;
  1259.     int resp;
  1260.  
  1261.     if (*LP) {
  1262.         for (i = 1; ; i = i < 32 ? i << 1 : i) {
  1263.             pfd = open(LP, RW ? O_RDWR : O_WRONLY);
  1264.             if (pfd >= 0)
  1265.             break;
  1266. #ifdef sprite
  1267.             if (RM != NULL) {
  1268.                 /*
  1269.                  * If couldn't open the device and a remote host
  1270.                  * is specified for the printer, go use TCP
  1271.                  * for the connection.
  1272.                  */
  1273.                 goto use_remote;
  1274.             }
  1275. #endif
  1276.             if (errno == ENOENT) {
  1277.                 syslog(LOG_ERR, "%s: %m", LP);
  1278.                 exit(1);
  1279.             }
  1280.             if (i == 1)
  1281.                 status("waiting for %s to become ready (offline ?)", printer);
  1282.             sleep(i);
  1283.         }
  1284.         if (isatty(pfd))
  1285.             setty();
  1286.         status("%s is ready and printing", printer);
  1287.     } else if (RM != NULL) {
  1288. use_remote:
  1289.         for (i = 1; ; i = i < 256 ? i << 1 : i) {
  1290.             resp = -1;
  1291.             pfd = getport(RM);
  1292.             if (pfd >= 0) {
  1293.                 (void) sprintf(line, "\2%s\n", RP);
  1294.                 n = strlen(line);
  1295.                 if (write(pfd, line, n) == n &&
  1296.                     (resp = response()) == '\0')
  1297.                     break;
  1298.                 (void) close(pfd);
  1299.             }
  1300.             if (i == 1) {
  1301.                 if (resp < 0)
  1302.                     status("waiting for %s to come up", RM);
  1303.                 else {
  1304.                     status("waiting for queue to be enabled on %s", RM);
  1305.                     i = 256;
  1306.                 }
  1307.             }
  1308.             sleep(i);
  1309.         }
  1310.         status("sending to %s", RM);
  1311.         remote = 1;
  1312.     } else {
  1313.         syslog(LOG_ERR, "%s: no line printer device or host name",
  1314.             printer);
  1315.         exit(1);
  1316.     }
  1317.     /*
  1318.      * Start up an output filter, if needed.
  1319.      */
  1320.     if (OF) {
  1321.         int p[2];
  1322.         char *cp;
  1323.  
  1324.         pipe(p);
  1325.         if ((ofilter = dofork(DOABORT)) == 0) {    /* child */
  1326.             dup2(p[0], 0);        /* pipe is std in */
  1327.             dup2(pfd, 1);        /* printer is std out */
  1328.             if ((cp = rindex(OF, '/')) == NULL)
  1329.                 cp = OF;
  1330.             else
  1331.                 cp++;
  1332.             if (debug) {
  1333.                 syslog(LOG_ERR, "execing %s %s, %d, %d",
  1334.                 OF, cp, width, length);
  1335.             }
  1336.             for (i = 3; i < NOFILE; i++)
  1337.                 (void) close(i);
  1338.             execl(OF, cp, width, length, 0);
  1339.             syslog(LOG_ERR, "%s: %s: %m", printer, OF);
  1340.             exit(1);
  1341.         }
  1342.         (void) close(p[0]);        /* close input side */
  1343.         ofd = p[1];            /* use pipe for output */
  1344.         if (debug) {
  1345.             syslog(LOG_ERR, "ofilter = %x, (%s)", ofilter, OF);
  1346.         }
  1347.     } else {
  1348.         ofd = pfd;
  1349.         ofilter = 0;
  1350.     }
  1351. }
  1352.  
  1353. struct bauds {
  1354.     int    baud;
  1355.     int    speed;
  1356. } bauds[] = {
  1357.     50,    B50,
  1358.     75,    B75,
  1359.     110,    B110,
  1360.     134,    B134,
  1361.     150,    B150,
  1362.     200,    B200,
  1363.     300,    B300,
  1364.     600,    B600,
  1365.     1200,    B1200,
  1366.     1800,    B1800,
  1367.     2400,    B2400,
  1368.     4800,    B4800,
  1369.     9600,    B9600,
  1370.     19200,    EXTA,
  1371.     38400,    EXTB,
  1372.     0,    0
  1373. };
  1374.  
  1375. /*
  1376.  * setup tty lines.
  1377.  */
  1378. setty()
  1379. {
  1380.     struct sgttyb ttybuf;
  1381.     register struct bauds *bp;
  1382. #ifdef sprite
  1383.     int family;
  1384. #endif
  1385.  
  1386. #ifndef sprite
  1387.     if (ioctl(pfd, TIOCEXCL, (char *)0) < 0) {
  1388.         syslog(LOG_ERR, "%s: ioctl(TIOCEXCL): %m", printer);
  1389.         exit(1);
  1390.     }
  1391. #endif
  1392.     if (ioctl(pfd, TIOCGETP, (char *)&ttybuf) < 0) {
  1393.         syslog(LOG_ERR, "%s: ioctl(TIOCGETP): %m", printer);
  1394.         exit(1);
  1395.     }
  1396.     if (BR > 0) {
  1397.         for (bp = bauds; bp->baud; bp++)
  1398.             if (BR == bp->baud)
  1399.                 break;
  1400.         if (!bp->baud) {
  1401.             syslog(LOG_ERR, "%s: illegal baud rate %d", printer, BR);
  1402.             exit(1);
  1403.         }
  1404.         ttybuf.sg_ispeed = ttybuf.sg_ospeed = bp->speed;
  1405.     }
  1406.     ttybuf.sg_flags &= ~FC;
  1407.     ttybuf.sg_flags |= FS;
  1408.     if (ioctl(pfd, TIOCSETP, (char *)&ttybuf) < 0) {
  1409.         syslog(LOG_ERR, "%s: ioctl(TIOCSETP): %m", printer);
  1410.         exit(1);
  1411.     }
  1412.     if (XC || XS) {
  1413.         int ldisc = NTTYDISC;
  1414.  
  1415.         if (ioctl(pfd, TIOCSETD, &ldisc) < 0) {
  1416.             syslog(LOG_ERR, "%s: ioctl(TIOCSETD): %m", printer);
  1417.             exit(1);
  1418.         }
  1419.     }
  1420.     if (XC) {
  1421.         if (ioctl(pfd, TIOCLBIC, &XC) < 0) {
  1422.             syslog(LOG_ERR, "%s: ioctl(TIOCLBIC): %m", printer);
  1423.             exit(1);
  1424.         }
  1425.     }
  1426.     if (XS) {
  1427.         if (ioctl(pfd, TIOCLBIS, &XS) < 0) {
  1428.             syslog(LOG_ERR, "%s: ioctl(TIOCLBIS): %m", printer);
  1429.             exit(1);
  1430.         }
  1431.     }
  1432.  
  1433. #ifdef sprite
  1434.     /*
  1435.      * Need to set the controlling group of the tty so we may manipulate
  1436.      * it.
  1437.      */
  1438.     Proc_GetFamilyID(PROC_MY_PID, &family);
  1439.     Ioc_SetOwner(pfd, family, IOC_OWNER_FAMILY);
  1440. #endif /* sprite */
  1441.  
  1442. }
  1443.  
  1444. /*VARARGS1*/
  1445. status(msg, a1, a2, a3)
  1446.     char *msg;
  1447. {
  1448.     register int fd;
  1449.     char buf[BUFSIZ];
  1450.  
  1451.     umask(0);
  1452.     fd = open(ST, O_WRONLY|O_CREAT, 0664);
  1453.     if (fd < 0 || flock(fd, LOCK_EX) < 0) {
  1454.         syslog(LOG_ERR, "%s: %s: %m", printer, ST);
  1455.         exit(1);
  1456.     }
  1457.     ftruncate(fd, 0);
  1458.     sprintf(buf, msg, a1, a2, a3);
  1459.     strcat(buf, "\n");
  1460.     (void) write(fd, buf, strlen(buf));
  1461.     (void) close(fd);
  1462. }
  1463.  
  1464.